package br.com.spam.pipeline.core;

public class Register
{
	private final String name;
	private int value;
	private RegisterDataSource lastWriteDataSource = RegisterDataSource.Register;
	private int lastWrite;

	public Register(String name, int value)
	{
		this.name = name;
		this.value = value;
		this.lastWrite = value;
	}

	public Register(String name)
	{
		this(name, 0);
	}

	public int getCorrectValue()
	{
		if (!(this.lastWriteDataSource.equals(RegisterDataSource.Register)
				|| this.lastWriteDataSource.equals(RegisterDataSource.EX)
				|| this.lastWriteDataSource.equals(RegisterDataSource.DM_EX) || this.lastWriteDataSource
				.equals(RegisterDataSource.DM_Memoria)))
			throw new IllegalStateException(
					"Devido a uma dependência, os dados desse registrador não podem ser lidos");

		return this.lastWrite;
	}

	public RegisterDataSource getCorrectValueDataSource()
	{
		return this.lastWriteDataSource;
	}

	public int getPersistedValue()
	{
		return this.value;
	}

	public void write(final int value, RegisterDataSource writeLocation)
	{
		this.lastWrite = value;
		this.lastWriteDataSource = writeLocation;
	}

	public String name()
	{
		return this.name;
	}

	public void lock()
	{
		this.lastWriteDataSource = RegisterDataSource.NotAvailable;
	}

	public void clockUp()
	{
		if (!this.lastWriteDataSource.equals(RegisterDataSource.NotAvailable))
		{
			this.lastWriteDataSource = this.getNextCycleDataSource();

			if (this.lastWriteDataSource.equals(RegisterDataSource.Register))
			{
				this.value = this.lastWrite;
			}
		}
	}

	public RegisterDataSource getNextCycleDataSource()
	{
		switch (this.lastWriteDataSource)
		{
			case DM_EX :
			case DM_Memoria :
				return RegisterDataSource.Register;
			case EX :
				return RegisterDataSource.DM_EX;
			case JustLoadedFromMemory :
				return RegisterDataSource.DM_Memoria;
			case JustCalculated :
				return RegisterDataSource.EX;
			case JustResolvedJump :
				return RegisterDataSource.Register;
			default :
				return RegisterDataSource.Register;
		}
	}

	public void release()
	{
		this.lastWriteDataSource = RegisterDataSource.Register;
	}
}
